int fun(int x){
    return x + 1;
}

int main() {
    int x = (1+2)*(3+4);
    {
        int x = 2;
        x = fun(x);
    }
    return x;
}

/*
运行过程解释（请对照这个逻辑检查汇编代码到底除了什么问题）
**临时数据分配：**

以“`int x = (1+2)*(3+4)`”中表达式"`(1+2)*(3+4)`”的临时数据分配为例

假设依次分配的内存编号依次为1，2，3....，初始状态，`NextPtr`为1

1.当前位于根结点“(1+2)*(3+4)”，准备先遍历“(1+2)”（step1），再遍历“(3+4)(step2)”

step1:遍历到子树“(1+2)”，进行后续遍历

2.遍历到叶子结点1，因为该结点没有子结点，故把临时数据1存入`NextPtr`，即1的位置，`NextPtr`前移一位，变为2

3.遍历到叶子结点2，因为该结点没有子结点，故把临时数据2存入`NextPtr`，即2的位置，`NextPtr`前移一位，变为3

4.遍历到结点“(1+2)”，该结点有两个子结点。故`NextPtr`后移两位（相当于退栈），变为1

~~由于Op为+，故分别把内存编号为【1】和【2】的位置ld到t0和t1，然后执行`add t0 t0 t1`，再把t0的值存入内存编号为【1】的位置~~

由于Op为+，由于操作数内存编号为【1】和【2】的位置分别为t2,t3，而运算结果内存编号为【1】，所以直接执行`add t2 t2 t3`

（对于上面划掉的内容，为如果操作数或运算结果内容在内存中的相应操作）

然后`NextPtr`前移一位，变为2

step2:遍历到子树“(3+4)”，进行后续遍历

5.遍历到叶子结点3，因为该结点没有子结点，故把临时数据3存入NextPtr，即2的位置，NextPtr前移一位，变为3

6.遍历到叶子结点4，因为该结点没有子结点，故把临时数据4存入NextPtr，即3的位置，NextPtr前移一位，变为4

7.遍历到结点“(3+4)”，该结点有两个子结点。故NextPtr后移两位（相当于退栈），变为2

~~由于Op为+，故分别把内存编号为【2】和【3】的位置ld到t0和t1，然后执行add t0 t0 t1，再把t0的值存入内存编号为【2】的位置~~

由于Op为+，由于操作数内存编号为【2】和【3】的位置分别为t3,t4，而运算结果内存编号为【2】，所以直接执行add t3 t3 t4

然后`NextPtr`后移一位，变为3

step3:遍历到根节点“(1+2)*(3+4)”，该结点有两个子结点。故NextPtr后移两位（相当于退栈），变为1

~~由于*两个操作数分别在【1】和【2】的位置，故分别把内存编号为【1】和【2】的位置ld到t0和t1，然后执行mul t0 t0 t1，再把t0的值存入内存编号为【1】的位置~~

由于*两个操作数分别在【1】和【2】的位置，而运算结果内存编号为【1】，故直接执行`mul t2 t2 t3`

然后`NextPtr`后移一位，变为2

step4（补充）：后续赋值操作

“=”左边为变量x，右边为`Expr`结果，`Expr`结果存在栈顶的位置，即1

`NextPtr`后移一位（相当于退栈），变为1

~~然后把内存变化为【1】（相当于从栈顶取出的元素）的位置ld到t0，再把t0的存入左边变量x对应的offset中~~

由于右值位于临时数据【1】，即`t2`，左值位于临时变量【1】，即`s0`，故不需要用`t0`和`t1`进行中转，直接执行`mv s0 t2`

**临时变量分配与作用域管理：**

分配阶段：

假设依次分配的内存编号依次为1，2，3....，初始状态，`NextPtr`为1

1.进入main函数，为main函数中的根作用域，Id编号为1，位于main函数作用域根结点

当前`NextPtr`为1，`BasePtr`栈为{1}  (识别main函数后面的"{"时，当前`NextPtr`即1弹入BasePtr栈),`scopeId`为1

2.识别“x=(1+2)*(3+4)”时，作用域1变量x分配当前`NextPtr`即1，`NextPtr`前移一位，变为2

3.下一句中，识别"{"，进入新的作用域，`scopeId`为2，注意，构建树中`scopeId`的父结点为1

BasePtr栈为{1，2}（当前`NextPtr`即2弹入BasePtr栈）

4.识别“int x = 2“时，作用域2变量x分配当前`NextPtr`即2，`NextPtr`前移一位，变为3

5.在fun函数中，作用域管理与main函数类似，注意不同的函数间的作用域无任何结点连接，相关独立，注意不同的函数不同作用域的`scopeId`唯一就行

（就是你如果先分配fun函数再分配main函数，fun函数作用域id为1，那main的作用域id就要从2开始）

6.第10行，识别"}"时，`NextPtr`变为`BasePtr`栈的栈顶即2，`BasePtr`栈弹出栈顶元素，变为{1}

7.第12行，main函数结束时，`NextPtr`变为1，`BasePtr`栈为{}

**代码生成阶段的查找：**

1.刚进入main函数时，作用域Id为1，查找x从结点1开始查找，找得到

2.进入子作用域时，作用域Id为2，查找x从结点2开始查找，找得到

备注：如果x在结点2找不到，那就依次向父结点开始查找，直到找到根结点
*/